package com.qzuser.sendmessagebasic.server.exchange;

import com.qzuser.sendmessagebasic.common.exception.ToolException;
import com.qzuser.sendmessagebasic.server.binding.Binding;
import com.qzuser.sendmessagebasic.server.message.Message;

public class Router {
    public boolean checkBindingKey(String bindingKey) {
        if (bindingKey == null || bindingKey.isEmpty()) {
            return true;
        }
        for (int i = 0; i < bindingKey.length(); i++) {
            char c = bindingKey.charAt(i);
            if (c >= '0' && c <= '9') {
                continue;
            }
            if (c >= 'a' && c <= 'z') {
                continue;
            }
            if (c >= 'A' && c <= 'Z') {
                continue;
            }
            if (c == '.' || c == '*' || c == '#' || c == '_') {
                continue;
            }
            return false;
        }
        String[] words = bindingKey.split("\\.");
        for (String word : words) {
            if (word.length() > 1 && (word.contains("*") || word.contains("#"))) {
                return false;
            }
        }
        for (int i = 0; i < words.length - 1; i++) {
            if (words[i].equals("*") && words[i + 1].equals("#")) {
                return false;
            }
            if (words[i].equals("#") && words[i + 1].equals("#")) {
                return false;
            }
            if (words[i].equals("#") && words[i + 1].equals("*")) {
                return false;
            }
        }
        return true;
    }

    public boolean checkRoutingKey(String routingKey) {
        if (routingKey == null || routingKey.isEmpty()) {
            return true;
        }
        for (int i = 0; i < routingKey.length(); i++) {
            char c = routingKey.charAt(i);
            if (c >= '0' && c <= '9') {
                continue;
            }
            if (c >= 'a' && c <= 'z') {
                continue;
            }
            if (c >= 'A' && c <= 'Z') {
                continue;
            }
            if (c == '.' || c == '_') {
                continue;
            }
            return false;
        }
        return true;
    }

    public boolean route(ExchangeType exchangeType, Binding binding, Message message) throws ToolException {
        if (exchangeType == ExchangeType.FANOUT) {
            return true;
        } else if (exchangeType == ExchangeType.TOPIC) {
            return topicRouter(binding, message);
        } else {
            throw new ToolException("[Router] 交换机类型非法：" + exchangeType);
        }
    }

    private boolean topicRouter(Binding binding, Message message) {
        String[] bindingKey = binding.getBindingKey().split("\\.");
        String[] routingKey = message.getRoutingKey().split("\\.");
        int bindingIndex = 0;
        int routingIndex = 0;
        while (bindingIndex != bindingKey.length && routingIndex != routingKey.length) {
            if (bindingKey[bindingIndex].equals("*")) {
                bindingIndex++;
                routingIndex++;
            } else if (bindingKey[bindingIndex].equals("#")) {
                bindingIndex++;
                if (bindingIndex == bindingKey.length) {
                    return true;
                }
                routingIndex = findNextIndex(routingKey, routingIndex, bindingKey[bindingIndex]);
                if (routingIndex == -1) {
                    return false;
                }
                bindingIndex++;
                routingIndex++;
            } else {
                if (!bindingKey[bindingIndex].equals(routingKey[routingIndex])) {
                    return false;
                }
                bindingIndex++;
                routingIndex++;
            }
        }
        return bindingIndex == bindingKey.length && routingIndex == routingKey.length;
    }

    private int findNextIndex(String[] routingKey, int routingIndex, String s) {
        while (routingIndex != routingKey.length) {
            if (routingKey[routingIndex].equals(s)) {
                return routingIndex;
            }
            routingIndex++;
        }
        return -1;
    }
}
